📝 Резюме · 📄 Оригинал (512 B)
https://t.me/Python_libr/3364
Обработка и отслеживание ошибок и исключений в Django
Источник: https://t.me/Python_libr/3364
Зачем нужна обработка исключений?
В веб-приложениях ошибки неизбежны. Правильная обработка исключений помогает:
- Предотвратить краши приложения
- Логировать ошибки для анализа
- Показать пользователю понятные сообщения
- Отслеживать проблемы в продакшене
Встроенный механизм Django
Django автоматически обрабатывает исключения и выводит 500 ошибки. Для кастомной обработки используйте декораторы и middleware:
from django.views.decorators.http import require_http_methods
from django.http import JsonResponse
import logging
logger = logging.getLogger(__name__)
# Базовый try-except в view
def get_user_data(request, user_id):
try:
user = User.objects.get(id=user_id)
return JsonResponse({'user': user.name})
except User.DoesNotExist:
logger.warning(f"User {user_id} not found")
return JsonResponse(
{'error': 'Пользователь не найден'},
status=404
)
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
return JsonResponse(
{'error': 'Внутренняя ошибка сервера'},
status=500
)
Декоратор для отслеживания ошибок
from functools import wraps
from django.http import JsonResponse
import traceback
import logging
logger = logging.getLogger(__name__)
def track_errors(view_func):
"""Декоратор для автоматического отслеживания ошибок"""
@wraps(view_func)
def wrapper(request, *args, **kwargs):
try:
return view_func(request, *args, **kwargs)
except Exception as e:
# Логируем ошибку с полным traceback
logger.error(
f"Error in {view_func.__name__}",
exc_info=True,
extra={
'method': request.method,
'path': request.path,
'user': request.user.id if request.user.is_authenticated else None
}
)
# Возвращаем JSON ответ с ошибкой
return JsonResponse(
{
'error': str(e),
'type': type(e).__name__
},
status=500
)
return wrapper
# Использование
@track_errors
def create_product(request):
data = request.POST
product = Product.objects.create(
name=data['name'],
price=float(data['price'])
)
return JsonResponse({'product_id': product.id})
Базовый класс для обработки исключений
from django.views import View
from django.http import JsonResponse
from django.core.exceptions import ValidationError
import logging
logger = logging.getLogger(__name__)
class BaseAPIView(View):
"""Базовый класс с обработкой ошибок"""
def dispatch(self, request, *args, **kwargs):
try:
return super().dispatch(request, *args, **kwargs)
except ValidationError as e:
logger.warning(f"Validation error: {e.message}")
return JsonResponse({'error': e.message}, status=400)
except ValueError as e:
logger.warning(f"Value error: {str(e)}")
return JsonResponse({'error': str(e)}, status=400)
except Exception as e:
logger.exception(f"Unhandled exception: {str(e)}")
return JsonResponse(
{'error': 'Внутренняя ошибка сервера'},
status=500
)
class ProductView(BaseAPIView):
def post(self, request):
price = float(request.POST['price']) # Может вызвать ValueError
product = Product.objects.create(
name=request.POST['name'],
price=price
)
return JsonResponse({'id': product.id})
Middleware для глобальной обработки
import json
import logging
from django.utils.deprecation import MiddlewareMixin
from django.http import JsonResponse
logger = logging.getLogger(__name__)
class ErrorHandlingMiddleware(MiddlewareMixin):
"""Middleware для перехвата всех ошибок"""
def process_exception(self, request, exception):
# Логируем исключение
logger.error(
f"Exception in {request.path}",
exc_info=True,
extra={
'method': request.method,
'user_id': request.user.id if request.user else None,
'remote_addr': self.get_client_ip(request)
}
)
# В development выводим детали, в production скрываем
if settings.DEBUG:
message = str(exception)
else:
message = 'Внутренняя ошибка сервера'
return JsonResponse({'error': message}, status=500)
@staticmethod
def get_client_ip(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
Диаграмма обработки исключений
graph TD
A["Request приходит"] --> B["View обрабатывает"]
B --> C{Возникла ошибка?}
C -->|Нет| D["Response отправляется"]
C -->|Да| E["Декоратор перехватывает"]
E --> F["Логируется"]
F --> G["Пользователю отправляется<br/>понятная ошибка"]
Лучшие практики
- Логируйте все: используйте Python
loggingдля записи всех ошибок - Не скрывайте детали: в development покажите полный traceback
- В production скройте детали: не раскрывайте техническую информацию
- Структурируйте логи: добавляйте контекст (user_id, path, метод)
- Используйте сервисы мониторинга: Sentry, DataDog для отслеживания в production
- Тестируйте обработку: создавайте тесты для ошибочных сценариев